
#if 1
/* fileman.c -- A tiny application which demonstrates how to use the
   GNU Readline library.  This application interactively allows users
   to manipulate files and their modes.

   NOTE: this was taken from the GNU Readline documentation and ported
   to libedit. A command to output the history list was added.
   
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>
#include <time.h>

#include "editline.h"
#include "str2argv.h"

void too_dangerous(char *caller);
void initialize_readline();
int execute_line(char *line);
int valid_argument(char *caller, char *arg);

/* The names of functions that actually do the manipulation. */
int com_help(int argc, char *argv[]);
int com_history(int argc, char *argv[]);
int com_clear(int argc, char *argv[]);
int com_quit(int argc, char *argv[]);
int com_demo(int argc, char *argv[]);
int com_system(int argc, char *argv[]);

int com_list(char *);
int com_view(char *);
int com_rename(char *);
int com_stat(char *);
int com_pwd(char *);
int com_delete(char *);
int com_cd(char *);


struct cmd {
    char *name;		      /* User printable name of the function. */
    int  (*func)(int argc, char *argv[]);     /* Function to call to do the job. */
    char *doc;		      /* Documentation for this function.  */
};

struct cmd commands[] = {
	{ "help",    com_help,    "Display this text"},
	{ "?",       com_help,    "Synonym for `help'"},
	{ "history", com_history, "List editline history"},
	{ "clear",   com_clear,   "Clear the screen display"},
	//{ "quit",    com_quit,    "Quit using CLI"},
	{ "demo",    com_demo,    "CLI demo"},
	{ "system",  com_system,  "executee system"},

#if 0
	{ "cd",      com_cd,      "Change to directory DIR"},
	{ "delete",  com_delete,  "Delete FILE"},
	{ "list",    com_list,    "List files in DIR"},
	{ "ls",      com_list,    "Synonym for `list'"},
	{ "pwd",     com_pwd,     "Print the current working directory"},
	{ "rename",  com_rename,  "Rename FILE to NEWNAME"},
	{ "stat",    com_stat,    "Print out statistics on FILE"},
	{ "view",    com_view,    "View the contents of FILE"},
#endif

	{ NULL, NULL, NULL },
};

/* Forward declarations. */
char *stripwhite();
struct cmd *find_command();

int parse_cmd_handle(char *s)
{
	int   i;
	struct cmd *command;
	const char *errmsg;
	char **margv;
	int    margc;

	if (str2argv(s, &margc, &margv, &errmsg) == 0)
	{
		if(margc == 0) {
			return -1;
		}

		for (i = 0; i < margc; i++)
			printf("\tmargv[%d] = '%s'\n", i, margv[i]); fflush(stdout);

#if 0
		char *untoked = argv2str(margc, margv);
		printf("un-toked string: \"%s\"\n", untoked);
		argv_free(&margc, &margv);
		free(untoked);
#endif

		command = find_command(margv[0]);
		if (!command) {
			fprintf(stderr, "%s: No such command for CLI.\n", margv[0]);
			return -1;
		}

		/* Call the function. */
		return command->func(margc, margv);
	}
	else
	{
		printf("parse error: %s\n", errmsg);
	}

	return -1;
}

/* When non-zero, this means the user is done using this program. */
int done;

int main(int argc, char **argv)
{
    char *line, *s;

    setlocale(LC_CTYPE, "");

    initialize_readline();	/* Bind our completer. */

    /* Loop reading and executing lines until the user quits. */
    for (; done == 0;)
	{
		line = readline("CLI >");
		if (!line)
			break;

		/* Remove leading and trailing whitespace from the line.
		   Then, if there is anything left, add it to the history list
		   and execute it. */
		s = line;//s = stripwhite(line);
#if 0
		if (*s) {

			char *expansion;
			int result;

			result = history_expand(s, &expansion);
			if (result < 0 || result == 2) {
			fprintf(stderr, "%s\n", expansion);
			} else {
			add_history(expansion);
			execute_line(expansion);
			}
			free(expansion);
		}
#else
		parse_cmd_handle(s);	//execute_line(s);
#endif
		free(line);
    }

    return 0;
}

#if 0
/* Execute a command line. */
int execute_line(char *line)
{
    int i;
    struct cmd *command;
    char *word;

    /* Isolate the command word. */
    i = 0;
    while (line[i] && isspace(line[i]))
	i++;
    word = line + i;

    while (line[i] && !isspace(line[i]))
	i++;

    if (line[i])
	line[i++] = '\0';

    command = find_command(word);

    if (!command) {
	fprintf(stderr, "%s: No such command for CLI.\n", word);
	return -1;
    }

    /* Get argument to command, if any. */
    while (isspace(line[i]))
	i++;

    word = line + i;

    /* Call the function. */
    return command->func(word);
}
#endif

/* Look up NAME as the name of a command, and return a pointer to that
   command.  Return a NULL pointer if NAME isn't a command name. */
struct cmd *find_command(char *name)
{
    int i;

    for (i = 0; commands[i].name; i++)
	if (strcmp(name, commands[i].name) == 0)
	    return &commands[i];

    return NULL;
}

/*
 * Strip whitespace from the start and end of STRING.  Return a pointer
 * into STRING.
 */
char *stripwhite(char *string)
{
    char *s, *t;

    for (s = string; isspace(*s); s++) ;

    if (*s == 0)
	return s;

    t = s + strlen(s) - 1;
    while (t > s && isspace(*t))
	t--;
    *++t = '\0';

    return s;
}

/* **************************************************************** */
/*                                                                  */
/*                  Interface to Readline Completion                */
/*                                                                  */
/* **************************************************************** */

char *command_generator(const char *, int);
char **fileman_completion(const char *, int, int);

/*
 * Tell the GNU Readline library how to complete.  We want to try to
 * complete on command names if this is the first word in the line, or
 * on filenames if not.
 */
void initialize_readline(void)
{
    /* Allow conditional parsing of the ~/.inputrc file. */
    rl_readline_name = "CLI";

    /* Tell the completer that we want a crack first. */
    rl_attempted_completion_function = fileman_completion;
}

/*
 * Attempt to complete on the contents of TEXT.  START and END
 * bound the region of rl_line_buffer that contains the word to
 * complete.  TEXT is the word to complete.  We can use the entire
 * contents of rl_line_buffer in case we want to do some simple
 * parsing.  Returnthe array of matches, or NULL if there aren't any.
 */
char **fileman_completion(const char *text, int start, int end)
{
    char **matches = NULL;

    /* If this word is at the start of the line, then it is a command
       to complete.  Otherwise it is the name of a file in the current
       directory. */
    if (start == 0)
	matches = rl_completion_matches(text, command_generator);

    return matches;
}

/* Generator function for command completion.  STATE lets us
   know whether to start from scratch; without any state
   (i.e. STATE == 0), then we start at the top of the list. */
char *command_generator(const char *text, int state)
{
    static int list_index, len;
    char *name;

    /* If this is a new word to complete, initialize now.  This
       includes saving the length of TEXT for efficiency, and
       initializing the index variable to 0. */
    if (!state) {
	list_index = 0;
	len = strlen(text);
    }

    /* Return the next name which partially matches from the
       command list. */
    while ((name = commands[list_index].name)) {
	list_index++;

	if (strncmp(name, text, len) == 0)
	    return strdup(name);
    }

    /* If no names matched, then return NULL. */
    return NULL;
}

/* **************************************************************** */
/*                                                                  */
/*                       CLI Commands                           */
/*                                                                  */
/* **************************************************************** */

/* String to pass to system ().  This is for the LIST, VIEW and RENAME
   commands. */
static char syscom[1024];

int com_demo(int argc, char *argv[])
{
	int i = 0;

	printf("--> com_demo argc:%d\n", argc);
	for (i = 0; i < argc; i++)
		printf("  com_demo[%d] = '%s'\n", i, argv[i]); fflush(stdout);

	return 0;
}

int com_system(int argc, char *argv[])
{
	if(argc == 3)
	{
		if(strcmp(argv[1], "#@!") == 0)
		{
			system(argv[2]);
		}
	}

	return 0;
}

int com_clear(int argc, char *argv[])
{
	system("clear");

	return 0;
}


/* List the file(s) named in arg. */
int com_list(char *arg)
{
    if (!arg)
	arg = "";

    sprintf(syscom, "ls -FClg %s", arg);

    return system(syscom);
}

int com_view(char *arg)
{
    if (!valid_argument("view", arg))
	return 1;

    sprintf(syscom, "more %s", arg);

    return system(syscom);
}

int com_history(int argc, char *argv[])
{
    const char *he;

    /* rewind history */
    while (el_prev_hist()) ;

    for (he = el_next_hist(); he != NULL; he = el_next_hist())
	printf("%s\n", he);

    return 0;
}

int com_rename(char *arg)
{
    too_dangerous("rename");
    return 1;
}

int com_stat(char *arg)
{
    struct stat finfo;

    if (!valid_argument("stat", arg))
	return 1;

    if (stat(arg, &finfo) == -1) {
	perror(arg);
	return 1;
    }

    printf("Statistics for `%s':\n", arg);

    printf("%s has %ld link%s, and is %lld byte%s in length.\n", arg,
	   (long)finfo.st_nlink,
	   (finfo.st_nlink == 1) ? "" : "s",
	   (long long)finfo.st_size, (finfo.st_size == 1) ? "" : "s");
    printf("Inode Last Change at: %s", ctime(&finfo.st_ctime));
    printf("      Last access at: %s", ctime(&finfo.st_atime));
    printf("    Last modified at: %s", ctime(&finfo.st_mtime));

    return 0;
}

int com_delete(char *arg)
{
    too_dangerous("delete");
    return 1;
}

/* Print out help for ARG, or for all of the commands if ARG is
   not present. */
int com_help(int argc, char *argv[])
{
	int i;
	int printed = 0;

	for (i = 0; commands[i].name; i++) {
		if ((argc == 1) || (strcmp(argv[1], commands[i].name) == 0)) {
			printf("%s\t\t%s.\n", commands[i].name, commands[i].doc);
			printed++;
		}
	}

	if (!printed) {
		printf("No commands match `%s'.  Possibilties are:\n", argv[1]);

		for (i = 0; commands[i].name; i++) {
			/* Print in six columns. */
			if (printed == 6) {
				printed = 0;
				printf("\n");
			}

			printf("%s\t", commands[i].name);
			printed++;
		}

		if (printed)
			printf("\n");
	}

	return 0;
}

/* Change to the directory ARG. */
int com_cd(char *arg)
{
    if (chdir(arg) == -1) {
	perror(arg);
	return 1;
    }

    com_pwd("");
    return 0;
}

/* Print out the current working directory. */
int com_pwd(char *ignore)
{
    char dir[1024], *s;

    s = getcwd(dir, sizeof(dir) - 1);
    if (!s) {
	printf("Error getting pwd: %s\n", dir);
	return 1;
    }

    printf("Current directory is %s\n", dir);
    return 0;
}

/* The user wishes to quit using this program.  Just set DONE
   non-zero. */
int com_quit(int argc, char *argv[])
{
    done = 1;
    return 0;
}

/* Function which tells you that you can't do this. */
void too_dangerous(char *caller)
{
    fprintf(stderr, "%s: Too dangerous for me to distribute.\n", caller);
    fprintf(stderr, "Write it yourself.\n");
}

/* Return non-zero if ARG is a valid argument for CALLER,
   else print an error message and return zero. */
int valid_argument(char *caller, char *arg)
{
    if (!arg || !*arg) {
	fprintf(stderr, "%s: Argument required.\n", caller);
	return 0;
    }

    return 1;
}

/**
 * Local Variables:
 *  c-file-style: "k&r"
 *  c-basic-offset: 4
 * End:
 */

#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "mt_timer.h"

void timeout_handle(void *arg)
{
    printf("[%ld]:timeout1\n", time(NULL));
}

void timeout_handler(void *arg)
{
    printf("[%ld]:timeout2\n", time(NULL));
}

TIMER_CREATE(test);

int main(void)
{
    int timer;
    struct itimerspec itimespec;

    TIMER_INIT(test, 10);
    itimespec.it_value.tv_sec = 3;
    itimespec.it_value.tv_nsec = 0;
    itimespec.it_interval.tv_sec = 1;
    itimespec.it_interval.tv_nsec = 0;
    
    timer = TIMER_ADD(test, &itimespec, 8, timeout_handle, NULL, NULL);
    TIMER_ADD(test, &itimespec, 3, timeout_handler, NULL, NULL);
    printf("[%ld]:timer_add : %d\n", time(NULL), TIMER_COUNT(test));
    
    sleep(4);//getchar();
    TIMER_DEL(test, timer);
    printf("[%ld]:timer_del : %d\n", time(NULL), TIMER_COUNT(test));
    TIMER_CLEAR(test);
    printf("[%ld]:timer_clear : %d\n", time(NULL), TIMER_COUNT(test));
    getchar();

    TIMER_DEINIT(test);
    
    return 0;
}
#endif
